# ordered_list.py

class ordered_list(list):
    r'''A list that can be accessed by index or key.

        >>> class foo(object):
        ...     def __init__(self, name): self.name = name
        ...     def __repr__(self): return "<foo {0}>".format(self.name)
        >>> ol = ordered_list()
        >>> ol.append(foo('a'))
        >>> ol.insert('a', foo('b'))
        >>> ol
        [<foo b>, <foo a>]
        >>> ol[0]
        <foo b>
        >>> ol['a']
        <foo a>
        >>> ol.index('a')
        1
        >>> ol.index('b')
        0
        >>> ol.index('c')
        Traceback (most recent call last):
        ...
        ValueError: ordered_list.index(x): 'c' not in list
        >>> del ol['b']
        >>> ol
        [<foo a>]
        >>> ol.append(foo('b'))
        >>> ol
        [<foo a>, <foo b>]
        >>> ol.append(foo('b'))
        Traceback (most recent call last):
        ...
        KeyError: "ordered_list.append(x): 'b' duplicate key"
    '''
    def __getitem__(self, i):
        if isinstance(i, (str, unicode)):
            i = self.index(i)
        return super(ordered_list, self).__getitem__(i)

    def __setitem__(self, i, value):
        if isinstance(i, (str, unicode)):
            i = self.index(i)
        return super(ordered_list, self).__setitem__(i, value)

    def __delitem__(self, i):
        if isinstance(i, (str, unicode)):
            i = self.index(i)
        return super(ordered_list, self).__delitem__(i)

    def __contains__(self, i):
        if isinstance(i, (str, unicode)):
            try:
                self.index(i)
                return True
            except ValueError:
                return False
        return super(ordered_list, self).__contains__(i)

    def index(self, key, start=None, end=None):
        if start is None: start = 0
        if start < 0: start += len(self)
        if start < 0: start = 0
        if start < len(self):
            if end is None: end = len(self)
            if end < 0: end += len(self)
            if end < 0: end = 0
            if end > len(self): end = len(self)
            for i in xrange(start, end):
                if self[i].name == key: return i
        raise ValueError("ordered_list.index(x): {0!r} not in list".format(key))

    def append(self, x):
        try:
            self.index(x.name)
            raise KeyError("ordered_list.append(x): {0!r} duplicate key"
                             .format(x.name))
        except ValueError:
            super(ordered_list, self).append(x)

    def insert(self, i, x):
        if isinstance(i, (str, unicode)):
            i = self.index(i)
        super(ordered_list, self).insert(i, x)

